﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Shared.Method
{
    public class BobBase
    {
        public const string I2CGet = "i2c get port 0 dev 0x{0} reg 0x{1}";
        public const string I2CSet = "i2c set port 0 dev 0x{0} reg 0x{1} data 0x{2}";

        public const string I2CGetDiag = "diag i2c get port 0 dev 0x{0} reg 0x{1}";
        public const string I2CSetDiag = "diag i2c set port 0 dev 0x{0} reg 0x{1} data 0x{2}";

        public static event Action<string> OnReturnString;

        /// <summary>
        /// read register
        /// </summary>
        /// <param name="tel">telnet second</param>
        /// <param name="reg">register address</param>
        /// <param name="index">register index</param>
        /// <returns></returns>
        public static byte ReadReg(YcdTelnetSecond tel, byte reg, byte index)
        {
            string cmdGetData = string.Format(I2CGet, Convert.ToString(reg, 16), Convert.ToString(index, 16));
            tel.SendAndRecv("diag", "RTK.0>", out string cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            bool bTelnet = tel.SendAndRecv(cmdGetData, "data:", out  cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);
            byte result = 0xFF;
            if (bTelnet) result = Convert.ToByte(cmdReturnStr.Substring(cmdReturnStr.IndexOf("data:") + 5, 5).Trim(), 16);

            tel.SendAndRecv("exit", "#", out  cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            return result;
        }
        public static byte[] ReadReg(YcdTelnetSecond tel, byte reg, byte startReg, byte endReg)
        {
            if (startReg > endReg) return null;

            byte[] result = new byte[endReg - startReg + 1];

            string cmdGetData;
            //string cmdReturnStr;
            bool bTelnet;

            tel.SendAndRecv("diag", "RTK.0>", out string cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            for (int i = startReg; i <= endReg; i++)
            {
                cmdGetData = string.Format(I2CGet, Convert.ToString(reg, 16), Convert.ToString(i, 16));
                bTelnet = tel.SendAndRecv(cmdGetData, "data:", out cmdReturnStr);
                OnReturnString?.Invoke(cmdReturnStr);
                if (bTelnet)
                {
                    result[i - startReg] = Convert.ToByte(cmdReturnStr.Substring(cmdReturnStr.IndexOf("data:") + 5, 5).Trim(), 16);
                }
            }

            tel.SendAndRecv("exit", "#", out cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            return result;
        }
        public static bool WriteReg(YcdTelnetSecond tel,byte reg,byte index,byte data)
        {
            tel.SendAndRecv("diag", "RTK.0>", out string cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            string cmdSetData = string.Format(I2CSet, Convert.ToString(reg, 16), Convert.ToString(index, 16), Convert.ToString(data, 16));
            bool bTelnet = tel.SendAndRecv(cmdSetData, "RTK.0>",  out  cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            tel.SendAndRecv("exit", "#", out cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            return bTelnet;
        }
        public static bool WriteReg(YcdTelnetSecond tel, byte reg, byte startReg, byte endReg,byte[] datas)
        {
            if (startReg > endReg || datas.Length != endReg - startReg + 1) return false;

            string cmdSetData;
            //string cmdReturnStr;
            bool bTelnet = false;

            tel.SendAndRecv("diag", "RTK.0>", out string cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            for (int i = startReg; i <= endReg; i++)
            {
                cmdSetData = string.Format(I2CSet, Convert.ToString(reg, 16), Convert.ToString(i, 16), Convert.ToString(datas[i - startReg], 16));
                bTelnet = tel.SendAndRecv(cmdSetData, "RTK.0>", out cmdReturnStr);
                OnReturnString?.Invoke(cmdReturnStr);
            }

            tel.SendAndRecv("exit", "#", out cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            return bTelnet;
        }
        public static bool WriteReg(YcdTelnetSecond tel, string reg, byte startReg, byte endReg, string datas)
        {
            if (startReg > endReg) return false;

            string cmdSetData;
            //string cmdReturnStr;
            bool bTelnet = false;

            datas = datas.Replace(" ", "").Replace("\r", "").Replace("\n", "").Replace("\t", "");
            tel.SendAndRecv("diag", "RTK.0>", out string cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            for (int i = endReg; i >= startReg; i--)
            {
                cmdSetData = string.Format(I2CSet, reg, Convert.ToString(i, 16), datas.Substring(2*(i-startReg),2));
                bTelnet = tel.SendAndRecv(cmdSetData, "RTK.0>", out cmdReturnStr);
                OnReturnString?.Invoke(cmdReturnStr);
            }

            tel.SendAndRecv("exit", "#", out cmdReturnStr);
            OnReturnString?.Invoke(cmdReturnStr);

            return bTelnet;
        }

        #region telnet third async
        public static void EnterDiag(YcdTelnetThird telnetThird)
        {
            telnetThird.Send("diag");
        }
        public static void ExitDiag(YcdTelnetThird telnetThird)
        {
            telnetThird.Send("exit");
        }
        public static void WriteReg(YcdTelnetThird tel, byte reg, byte index, byte data)
        {
            string cmdSetData = string.Format(I2CSet, Convert.ToString(reg, 16), Convert.ToString(index, 16), Convert.ToString(data, 16));
            tel.Send(cmdSetData);
        }
        public static void WriteReg(YcdTelnetThird tel, byte reg, byte startReg, byte endReg, byte[] datas)
        {
            if (startReg > endReg || datas == null || datas.Length != endReg - startReg + 1) return;

            string cmdSetData;

            //tel.Send("diag");

            for (int i = startReg; i <= endReg; i++)
            {
                cmdSetData = string.Format(I2CSet, Convert.ToString(reg, 16), Convert.ToString(i, 16), Convert.ToString(datas[i - startReg], 16));
                tel.Send(cmdSetData);
            }

            //tel.Send("exit");

            //if (tel.LastMsg.Contains("#")==false)
            //{
            //    System.Threading.Thread.Sleep(1000);
            //}
        }
        public static void WriteReg(YcdTelnetThird tel, string reg, byte startReg, byte endReg, string datas)
        {
            if (startReg > endReg || datas==null) return;

            string cmdSetData;

            datas = datas.Replace(" ", "").Replace("\r", "").Replace("\n", "").Replace("\t", "");
            //tel.Send("diag");

            for (int i = endReg; i >= startReg; i--)
            {
                cmdSetData = string.Format(I2CSet, reg, Convert.ToString(i, 16), datas.Substring(2 * (i - startReg), 2));
                 tel.Send(cmdSetData);
            }

            //tel.Send("exit");
        }
        public static byte ReadReg(YcdTelnetThird tel, byte reg, byte index)
        {
            tel.SetRecord();

            string cmdGetData = string.Format(I2CGet, Convert.ToString(reg, 16), Convert.ToString(index, 16));

            //tel.Send("diag");

            tel.Send(cmdGetData);

            System.Threading.Thread.Sleep(400);

            string record = tel.GetRecordStr();

            byte result = 0;

            if (string.IsNullOrEmpty(record) == false)
                result = Convert.ToByte(record.Substring(record.IndexOf("data:") + 5, 5).Trim(), 16);

            tel.SetNotRecord();

            return result;
        }
        public static List<byte> ReadReg(YcdTelnetThird tel, byte reg, byte startReg, byte endReg)
        {
            if (startReg > endReg) return null;

            tel.SetRecord();

            List<byte> result = new List<byte>();

            string cmdGetData;

            //tel.Send("diag");

            //System.Threading.Thread.Sleep(300);

            for (int i = startReg; i <= endReg; i++)
            {
                cmdGetData = string.Format(I2CGet, Convert.ToString(reg, 16), Convert.ToString(i, 16));
                tel.Send(cmdGetData);
            }

            System.Threading.Thread.Sleep(400);

            string recordMsg = tel.GetRecordStr();

            //if (string.IsNullOrEmpty(recordMsg)) return null;

            for (int i = 0; i < recordMsg.Length - 8; i++)//去掉最后一行，及其回车换行符号
            {
                if (
                    recordMsg.ElementAt(i) == 'd'
                    && recordMsg.ElementAt(i + 1) == 'a'
                    && recordMsg.ElementAt(i + 2) == 't'
                    && recordMsg.ElementAt(i + 3) == 'a'
                    && recordMsg.ElementAt(i + 4) == ':'
                    )
                {
                    result.Add(Convert.ToByte(recordMsg.Substring(i + 5, 5).Trim(), 16));
                    i += 10;
                }
            }

            //tel.Send("exit");

            tel.SetNotRecord();

            return result;
        }

        #endregion
        /// <summary>
        /// bytes to int
        /// </summary>
        /// <param name="input">bytes</param>
        /// <param name="tenBits">boo ten bit</param>
        /// <returns></returns>
        public static int Bytes2Int(byte[] input, bool tenBits)
        {
            if (input.Length != 2) return 0;

            int result;

            if (tenBits)
            {
                result = (input[0] << 2) + (input[1] & 3);//input[0]<<2 & input[1]&00000011
            }
            else
            {
                result = (input[0] << 8) + input[1];
            }

            return result;
        }
        /// <summary>
        /// Int to Bytes
        /// </summary>
        /// <param name="input">input</param>
        /// <param name="tenBits">bool ten bits</param>
        /// <returns></returns>
        public static byte[] Int2Bytes(int input, bool tenBits)
        {
            if (input < 0) return null;

            byte[] result = new byte[2];

            if (tenBits)
            {
                result[1] = (byte)(input & 3);
                result[0] = (byte)((input >> 2) & 0xFF);
            }
            else
            {
                result[1] = (byte)(input & 0xFF);
                result[0] = (byte)((input >> 8) & 0xFF);
            }

            return result;
        }
        /// <summary>
        /// 修改byte中某位的值
        /// </summary>
        /// <param name="input">byte value</param>
        /// <param name="bitAddr">0-7</param>
        /// <param name="bitOne">true or false</param>
        /// <returns></returns>
        public static byte ChangeBit(byte input, ushort bitAddr, bool bitOne)
        {
            if (bitAddr >= 8) return 0;

            int result = 0;

            int bitValue = (input >> bitAddr) % 2;

            if (bitOne && bitValue == 0)
            {
                result += ((input >> bitAddr) + 1) << bitAddr;
                result += ((input << (8 - bitAddr)) & 0xFF) >> (8 - bitAddr);
            }
            else if (bitOne == false && bitValue == 1)
            {
                result += ((input >> bitAddr) - 1) << bitAddr;
                result += ((input << (8 - bitAddr)) & 0xFF) >> (8 - bitAddr);
            }
            else
            {
                result = input;
            }

            return (byte)result;
        }

        public static byte ChangeLastTwoBits(byte input, byte lastbits)
        {
            if (lastbits < 0 || lastbits > 3) return 0xFF;

            return (byte)(((input >> 2) << 2) + lastbits);
        }

        public static double DBm2mW(double power_dBm)
        {
            double power_mW = Math.Pow(10, power_dBm / 10);

            return power_mW;
        }

        public static List<byte> Tlut2Table(List<int> tlut)
        {
            if (tlut == null || tlut.Count == 0) return null;

            List<byte> table = new List<byte>();
            byte tempByte;
            int tlut1, tlut2, tlut3, tlut4;

            for (int i = 0; i < tlut.Count / 4; i++)
            {
                tlut1 = tlut[i * 4];
                tlut2 = tlut[i * 4 + 1];
                tlut3 = tlut[i * 4 + 2];
                tlut4 = tlut[i * 4 + 3];

                tempByte = (byte)(tlut1 / 4);
                table.Add(tempByte);

                tempByte = (byte)((tlut1 & 0x03) * 64 + tlut2 / 16);
                table.Add(tempByte);

                tempByte = (byte)((tlut2 & 0x0F) * 16 + tlut3 / 64);
                table.Add(tempByte);

                tempByte = (byte)((tlut3 & 0x3F) * 4 + tlut4 / 256);
                table.Add(tempByte);

                tempByte = (byte)(tlut4 & 0xFF);
                table.Add(tempByte);
            }

            return table;
        }

        public static List<int> Table2Tlut(List<byte> table)
        {
            if (table == null || table.Count == 0) return null;

            List<int> tlut = new List<int>();
            int tempLut;
            byte b1, b2, b3, b4, b5;
            for (int i = 0; i < table.Count / 5; i++)
            {
                b1 = table[i * 5];
                b2 = table[i * 5 + 1];
                b3 = table[i * 5 + 2];
                b4 = table[i * 5 + 3];
                b5 = table[i * 5 + 4];

                tempLut = b1 * 4 + b2 / 64;
                tlut.Add(tempLut);

                tempLut = (b2 & 0x3F) * 16 + b3 / 16;
                tlut.Add(tempLut);

                tempLut = (b3&0x0F) * 64 + b4 / 4;
                tlut.Add(tempLut);

                tempLut = (b4 & 0x03) * 256 + b5;
                tlut.Add(tempLut);
                
            }

            return tlut;
        }
    }
}
